/**
  *******************************************************************************
  * @author   正点原子@ALIENTEK
  *           技术论坛 {@link www.openedv.com}
  *
  * @file     alientek_usart.c
  * @brief    USART1 init. To use this file, you need:
  *           1. add stm32f1xx_hal_uart.c and stm32f1xx_hal_uart.h in directory Drivers/STM32F1XX_HAL_Driver
  *           2. Enable HAL_UART_MODULE_ENABLED in file Core/Inc/stm32f1xx_hal_conf.h
  *
  * @note     Stm32_Clock_Init(u32 PLL): System Clock Init.
  *
  *******************************************************************************
  * Change Logs:
  *   Date           Author       Notes
  *   2010-01-01     ALIENTEK     the first version
  *                  v1.3         支持适应不同频率下的串口波特率设置.
  *                               加入了对printf的支持
  *                               增加了串口接收命令功能.
  *                               修正了printf第一个字符丢失的bug
  *                  v1.4         修改串口初始化IO的bug
  *                               修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
  *                               增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
  *                               修改了EN_USART1_RX的使能方式
  *   2012-08-18     v1.5         增加了对UCOSII的支持
  *******************************************************************************
  * @attention
  *
  *  本程序只供学习使用，未经作者许可，不得用于其它任何用途
  *  版权所有，盗版必究。
  *  Copyright (c) 广州市星翼电子科技有限公司 2009-2023
  *  All rights reserved.
  *******************************************************************************
  */

#include "alientek_sys.h"
#include "alientek_usart.h"

#if SYSTEM_SUPPORT_OS
#include "includes.h"     // ucos 使用
#endif


// 加入以下代码，支持 printf 函数，而不需要选择 use MicroLIB
#define PUT_CHAR_PROTOTYPE int __io_putchar(int ch)

PUT_CHAR_PROTOTYPE
{
  while ((USART1->SR & 0X40) == 0); // 循环发送,直到发送完毕
  USART1->DR = (u8) ch;
  return ch;
}


#if EN_USART1_RX                  // 如果使能了接收
// 串口 1 中断服务程序
// 注意，读取 USARTx->SR 能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN];   // 接收缓冲，最大 USART_REC_LEN 个字节。

// 接收状态：
// bit15，	接收完成标志
// bit14，	接收到0x0d
// bit13~0，	接收到的有效字节数目
u16 USART_RX_STA = 0;             // 接收状态标记

u8 aRxBuffer[RXBUFFERSIZE];       // HAL 库使用的串口接收缓冲
UART_HandleTypeDef UART1_Handler; // UART 句柄

/**
 * 初始化 IO 串口 1
 * @param bound 波特率
 */
void uart_init(u32 bound)
{
  // UART 初始化设置
  UART1_Handler.Instance = USART1;                    // USART1
  UART1_Handler.Init.BaudRate = bound;                // 波特率
  UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B; // 字长为8位数据格式
  UART1_Handler.Init.StopBits = UART_STOPBITS_1;      // 一个停止位
  UART1_Handler.Init.Parity = UART_PARITY_NONE;       // 无奇偶校验位
  UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控
  UART1_Handler.Init.Mode = UART_MODE_TX_RX;          // 收发模式

  // 该函数会使能 UART1
  HAL_UART_Init(&UART1_Handler);

  // 该函数会开启接收中断：标志位UART_IT_RXNE，并且设置接收缓冲以及接收缓冲接收最大数据量
  HAL_UART_Receive_IT(&UART1_Handler, (u8 *) aRxBuffer, RXBUFFERSIZE);
}


/**
 * UART 底层初始化，时钟使能，引脚配置，中断配置。此函数会被 HAL_UART_Init() 调用
 * @param huart 串口句柄
 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  // GPIO端口设置
  GPIO_InitTypeDef GPIO_Initure;

  if (huart->Instance == USART1)  // 如果是串口 1，进行串口 1 MSP 初始化
  {
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能 GPIOA 时钟
    __HAL_RCC_USART1_CLK_ENABLE();// 使能 USART1 时钟
    __HAL_RCC_AFIO_CLK_ENABLE();

    GPIO_Initure.Pin = GPIO_PIN_9;          // PA9
    GPIO_Initure.Mode = GPIO_MODE_AF_PP;    // 复用推挽输出
    GPIO_Initure.Pull = GPIO_PULLUP;        // 上拉
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;            // 高速
    HAL_GPIO_Init(GPIOA, &GPIO_Initure); // 初始化 PA9

    GPIO_Initure.Pin = GPIO_PIN_10;         // PA10
    GPIO_Initure.Mode = GPIO_MODE_AF_INPUT; // 模式要设置为复用输入模式！
    HAL_GPIO_Init(GPIOA, &GPIO_Initure); // 初始化PA10

#if EN_USART1_RX
    HAL_NVIC_EnableIRQ(USART1_IRQn);  // 使能USART1中断通道
    HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);// 抢占优先级3，子优先级3
#endif
  }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)//如果是串口1
  {
    if ((USART_RX_STA & 0x8000) == 0)//接收未完成
    {
      if (USART_RX_STA & 0x4000)//接收到了0x0d
      {
        if (aRxBuffer[0] != 0x0a)USART_RX_STA = 0;//接收错误,重新开始
        else USART_RX_STA |= 0x8000;  //接收完成了
      } else //还没收到0X0D
      {
        if (aRxBuffer[0] == 0x0d)USART_RX_STA |= 0x4000;
        else
        {
          USART_RX_BUF[USART_RX_STA & 0X3FFF] = aRxBuffer[0];
          USART_RX_STA++;
          if (USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0;//接收数据错误,重新开始接收
        }
      }
    }

  }
}

// 串口1中断服务程序
void USART1_IRQHandler(void)
{
  u32 timeout = 0;
#if SYSTEM_SUPPORT_OS    //使用OS
  OSIntEnter();
#endif

  HAL_UART_IRQHandler(&UART1_Handler);  //调用HAL库中断处理公用函数

  timeout = 0;
  while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)//等待就绪
  {
    timeout++;////超时处理
    if (timeout > HAL_MAX_DELAY) break;

  }

  timeout = 0;
  while (HAL_UART_Receive_IT(&UART1_Handler, (u8 *) aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次处理完成之后，重新开启中断并设置RxXferCount为1
  {
    timeout++; //超时处理
    if (timeout > HAL_MAX_DELAY) break;
  }
#if SYSTEM_SUPPORT_OS    //使用OS
  OSIntExit();
#endif
}

#endif

/*下面代码我们直接把中断控制逻辑写在中断服务函数内部。*/

//串口1中断服务程序
//void USART1_IRQHandler(void)                	
//{ 
//	u8 Res;
//	HAL_StatusTypeDef err;
//#if SYSTEM_SUPPORT_OS	 	//使用OS
//	OSIntEnter();    
//#endif
//	if((__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_RXNE)!=RESET))  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
//	{
//		Res=USART1->DR; 
//		if((USART_RX_STA&0x8000)==0)//接收未完成
//		{
//			if(USART_RX_STA&0x4000)//接收到了0x0d
//			{
//				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
//				else USART_RX_STA|=0x8000;	//接收完成了 
//			}
//			else //还没收到0X0D
//			{	
//				if(Res==0x0d)USART_RX_STA|=0x4000;
//				else
//				{
//					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
//					USART_RX_STA++;
//					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
//				}		 
//			}
//		}   		 
//	}
//	HAL_UART_IRQHandler(&UART1_Handler);	
//#if SYSTEM_SUPPORT_OS	 	//使用OS
//	OSIntExit();  											 
//#endif
//} 
//#endif	


